package qc.common.core.utils;

import org.apache.commons.lang3.StringUtils;

import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.List;

/**
 * 进制工具类，提供byte、int、ascii、hex之间的互转
 * byte能表示的范围是-127~127，比如0xC1 对应十进制数值为193，如果使用byte类型其数值为-63
 *
 * @author QuCheng Tech
 * @since 2025/11/7
 */
public class RadixConvertUtil {
    /**
     * 计算byte对应的int值；由于byte表示的范围是-127~127，byte无法表示≥128以上的情况，使用byte对应的hex字符串转换为对应的int值
     *
     * @param b byte值
     * @return int 返回的值在0~255
     * @author QuCheng Tech
     * @since 2025/11/12
     */
    public static int computeIntValue(byte b) {
        String hex = toHexString(b);
        try {
            return hexStringToIntValue(hex);
        } catch (NumberFormatException ex) {
            //转换错误不处理，默认为0
        }

        return 0x0;
    }

    /**
     * byte数组直接转换为int数值，byte数组转换为对应的hex字符串，十六进制转换为十进制数值
     *
     * @param bytes byte数组
     * @return int
     * @author QuCheng Tech
     * @since 2025/11/16
     */
    public static int computeIntValue(byte[] bytes) {
        String hex = toHexString(bytes);
        try {
            return hexStringToIntValue(hex);
        } catch (NumberFormatException ex) {
            //转换错误不处理，默认为0
        }

        return 0x0;
    }

    /**
     * 计算高低位2个字节对应的int值
     *
     * @param highIntValue 高位字节
     * @param lowIntValue  低位字节
     * @return int
     * @author QuCheng Tech
     * @since 2025/11/7
     */
    public static int computeIntValue(int highIntValue, int lowIntValue) {
        int result = computeIntValue(new int[]{highIntValue, lowIntValue});

        //System.out.println("高位：" + (highIntValue & 0xFF) + "，低位：" + (lowIntValue & 0xFF) + " 结果值：" + result);

        return result;
    }

    /**
     * int数组计算为对应的int值，默认高位字节在前
     *
     * @param byteIntValues 字节数值数组
     * @return int
     * @author QuCheng Tech
     * @since 2025/11/7
     */
    public static int computeIntValue(int[] byteIntValues) {
        return computeIntValue(byteIntValues, false);
    }

    /**
     * int数组计算为对应的int值，指定高位字节是在前还是在后
     *
     * @param byteIntValues   字节数值数组
     * @param isLowByteBefore 指定高位字节是在前还是在后
     * @return int
     * @author QuCheng Tech
     * @since 2025/11/8
     */
    public static int computeIntValue(int[] byteIntValues, boolean isLowByteBefore) {
        //初始化计算出的int值为0
        int result = 0x0;

        if (byteIntValues != null && byteIntValues.length > 0x0) {
            if (isLowByteBefore == false) {
                //高位在前
                for (int i = 0; i < byteIntValues.length; i++) {
                    //字节数组从后往前获取处理，从后往前第n个字节左移n-1个8位后累加到返回结果值上
                    int b = byteIntValues[byteIntValues.length - i - 1] & 0xFF;//与0xFF做与运算，避免出现超出0-255范围的错误数值
                    if (b > 0x0) {//当前字节数值＞0才当做有效值
                        //如果不需要向左移位则不进行移位操作
                        if (i > 0x0)
                            result += (b << (0x8 * i));
                        else
                            result += b;
                    }
                }
            } else {
                //低位在前
                for (int i = 0; i < byteIntValues.length; i++) {
                    //字节数组从前往后获取处理，从前往后第n个字节左移n-1个8位后累加到返回结果值上
                    int b = byteIntValues[i] & 0xFF;//与0xFF做与运算，避免出现超出0-255范围的错误数值
                    if (b > 0x0) {//当前字节数值＞0才当做有效值
                        //如果不需要向左移位则不进行移位操作
                        if (i > 0x0)
                            result += (b << (0x8 * i));
                        else
                            result += b;
                    }
                }
            }
        }

        return result;
    }

    /**
     * 计算使用BCD编码的字节表示值，无符号位，计算值为非负整数
     *
     * @param b 字节
     * @return int
     * @author QuCheng Tech
     * @since 2025/11/13
     */
    public static int computeBcdIntValue(byte b) {
        return computeBcdIntValue(b, false, 0x0);
    }

    /**
     * 计算使用BCD编码的字节表示值
     *
     * @param b                字节
     * @param isHighByteBefore 字节数组中是否高位在前，默认是低位在前高位在后
     * @return int
     * @author QuCheng Tech
     * @since 2025/11/13
     */
    public static int computeBcdIntValue(byte b, boolean isHighByteBefore) {
        return computeBcdIntValue(b, isHighByteBefore, 0x0);
    }

    /**
     * 计算使用BCD编码的字节表示值
     *
     * @param b            字节
     * @param signBitCount 符号位的位数，可以为0-4；用最后一个字节的高4为表示符号，对应位数为0表示正 为1表示负
     * @return int
     * @author QuCheng Tech
     * @since 2025/11/13
     */
    public static int computeBcdIntValue(byte b, int signBitCount) {
        return computeBcdIntValue(b, false, signBitCount);
    }

    /**
     * 计算使用BCD编码的字节表示值
     *
     * @param b                字节
     * @param isHighByteBefore 字节数组中是否高位在前，默认是低位在前高位在后
     * @param signBitCount     符号位的位数，可以为0-4；用最后一个字节的高4为表示符号，对应位数为0表示正 为1表示负
     * @return int
     * @author QuCheng Tech
     * @since 2025/11/13
     */
    public static int computeBcdIntValue(byte b, boolean isHighByteBefore, int signBitCount) {
        return computeBcdIntValue(new byte[]{b}, isHighByteBefore, signBitCount);
    }

    /**
     * 转换BCD码对应的数值，数值为正整数
     *
     * @param bytes 字节数组
     * @return double
     * @author QuCheng Tech
     * @since 2025/11/13
     */
    public static int computeBcdIntValue(byte[] bytes) {
        return computeBcdIntValue(bytes, false, 0x0);
    }

    /**
     * 转换BCD码对应的数值
     *
     * @param bytes        字节数组
     * @param signBitCount 符号位的位数，可以为0-4；用最后一个字节的高4为表示符号，对应位数为0表示正 为1表示负
     * @return double
     * @author QuCheng Tech
     * @since 2025/11/13
     */
    public static int computeBcdIntValue(byte[] bytes, int signBitCount) {
        return computeBcdIntValue(bytes, false, signBitCount);
    }

    /**
     * 转换BCD码对应的数值
     *
     * @param bytes            字节数组
     * @param isHighByteBefore 字节数组中是否高位在前，默认是低位在前高位在后
     * @return double
     * @author QuCheng Tech
     * @since 2025/11/13
     */
    public static int computeBcdIntValue(byte[] bytes, boolean isHighByteBefore) {
        return computeBcdIntValue(bytes, isHighByteBefore, 0x0);
    }

    /**
     * 转换BCD码对应的数值
     *
     * @param bytes            字节数组
     * @param isHighByteBefore 是否高位在前，同时作用于字节数组的顺序和单个字节中的高低4位的顺序；字节数组中是否高位在前，默认是低位在前高位在后
     * @param signBitCount     符号位的位数，可以为0-4；用最后一个字节的高4为表示符号，对应位数为0表示正 为1表示负
     * @return double
     * @author QuCheng Tech
     * @since 2025/11/13
     */
    public static int computeBcdIntValue(byte[] bytes, boolean isHighByteBefore, int signBitCount) {
        //BCD码对应的数值解析方法：默认字节数组按低位到高位的顺序，每个字节的高4位和低4位分别表示一个位数上的数值（0-9），传入的系数表示最低位数上的系数
        //最后一个字节的最高1位是否表示符号，如果表示符号时为0表示正数、为1表示负数
        //比如3字节的BCD码：第1字节至第3字节的各高4位和低4位依次表示：个位、十分位、百位、、十位、万位(符号位)、千位
        //比如5字节的BCD码：第1字节至第5字节的各高4位和低4位依次表示：百分位、千分位、个位、十分位、百位、、十位、万位、千位、百万位(符号位)、十万位
        //比如5字节的BCD码：第1字节至第5字节的各高4位和低4位依次表示：十位、个位、千位、百位、十万位、万位、千万位、百万位、十亿位(符号位)、亿位
        if (bytes != null && bytes.length > 0x0) {
            //先默认按照第1个字节的高4位和低4位表示十位和个位，统计计算完成后再进行系数转换
            int intValue = 0x0;
            int digit = 1;//位数对应需要乘以的数值，后面每计算一个位数后乘以10
            boolean isNegative = false;//符号位标识是否为负值
            for (int i = 0; i < bytes.length; i++) {
                //先取出高4位和低4位的byte值：高4位对应字节的值先右移4位（转换为byte数值的范围内），变成只有低4位后再做与运算
                //高4位的值，判断如果最后一个字节的最高位是否表示符号位
                //取字节数组的索引，如果是低位在前就按i的顺序获取，如果是高位在前要倒序获取
                int getByteIndex = i;
                if (isHighByteBefore == true)
                    getByteIndex = bytes.length - 0x1 - i;//索引从0开始，需要用长度-1
                int lowValue = bytes[getByteIndex] & 0x0F;
                int highValue = (bytes[getByteIndex] >> 0x4) & 0x0F;
                if (signBitCount > 0x0 && getByteIndex == bytes.length - 0x1) {
                    //如果表示符号位位数＞0，需要处理最后一个字节高位中的符号
                    int signValue = 0x08;//1位表示符号位
                    if (signBitCount == 0x2)
                        signValue = 0x0C;//2位表示符号位
                    else if (signBitCount == 0x3)
                        signValue = 0x0E;//3位表示符号位
                    else if (signBitCount == 0x4)
                        signValue = 0x0F;//4位表示符号位

                    if ((highValue & signValue) == signValue) {
                        //符号位全部为1，表示符号位为负
                        isNegative = true;
                        //高4位的值=符号位值取反后做与运算
                        highValue = highValue & (~signValue);
                    }
                }

                //if(isHighByteBefore==true){
                //    //高位在前：高4位表示高位上的值、低4位表示低位上的值
                //    //先加低位的值，再加高位的值；
                //    intValue += digit * lowValue;
                //    digit *= 10;
                //
                //    //高4位的值累加，计算后乘以10
                //    intValue += digit * highValue;
                //    digit *= 10;
                //}else{
                //    //低位在前：高4位表示低位上的值、低4位表示高位上的值
                //    //低4位的值累加，计算后乘以10
                //    intValue += digit * lowValue;
                //    digit *= 10;
                //
                //    //高4位的值累加，计算后乘以10
                //    intValue += digit * highValue;
                //    digit *= 10;
                //}
                //低4位的值累加，计算后乘以10
                intValue += digit * lowValue;
                digit *= 10;

                //高4位的值累加，计算后乘以10
                intValue += digit * highValue;
                digit *= 10;
            }

            //System.out.println("parseBinaryCodeDecimal bytes=" + toHexString(bytes) + " 计算出int值=" + intValue + " 符号位数=" + signBitCount);

            //如果符号位判断为负，取负值
            if (isNegative == true)
                return -intValue;

            return intValue;
        }

        return 0x0;
    }

    /**
     * 计算字节数组对应的int设置
     *
     * @param bytes 字节数组
     * @return int
     * @author QuCheng Tech
     * @since 2025/11/15
     */
    public static int computeAsciiIntValue(byte[] bytes) {
        return computeAsciiIntValue(bytes, false);
    }

    /**
     * 计算字节数组对应的int设置
     *
     * @param bytes            字节数组
     * @param isHighByteBefore 是否高位字节在前
     * @return int
     * @author QuCheng Tech
     * @since 2025/11/15
     */
    public static int computeAsciiIntValue(byte[] bytes, boolean isHighByteBefore) {
        if (bytes != null && bytes.length > 0x0) {
            int result = 0x0;

            int modulus = 1;//系数，每处理完1个字节乘以10
            for (int i = 0; i < bytes.length; i++) {
                byte b = bytes[i];
                //如果是高位在前要逆序获取
                if (isHighByteBefore == true)
                    b = bytes[bytes.length - i - 0x1];

                //Hex 30~39表示数字0~9字符，对应int值为60~71
                String asciiStr = String.valueOf((char) b);//先将byte转换为char，再直接使用char对应的字符串转换为int
                int intValue = Integer.parseInt(asciiStr);
                //System.out.println("computeAsciiIntValue byte=" + b + " int=" + intValue);
                result += intValue * modulus;

                modulus *= 10;//系数*10
            }

            return result;
        }

        return 0x0;
    }

    /**
     * 十六进制字符串转换为对应的int值，如字符串2F对应的int值为47
     *
     * @param hexString 十六进制字符串
     * @return int 返回-1表示错误
     * @author QuCheng Tech
     * @since 2025/11/10
     */
    public static int hexStringToIntValue(String hexString) {
        if (StringUtils.isNotBlank(hexString)) {
            //如果十六进制字符串为空不能进行转换对应的int值
            try {
                int intValue = Integer.parseInt(hexString, 16);

                return intValue;
            } catch (NumberFormatException ex) {
                //如果是有数值转换错误不抛出异常，默认返回-1表示错误
            }
        }

        return -1;
    }

    /**
     * 将int型数值转换为byte数组，必须指定byte数组的长度；默认按照先高位后低位的顺序返回数组
     *
     * @param value  数值
     * @param length 字节数组的长度
     * @return int[]
     * @author QuCheng Tech
     * @since 2025/11/8
     */
    public static int[] toByteArray(int value, int length) {
        return toByteArray(value, length, false);
    }

    /**
     * 将int型数值转换为byte数组，必须指定byte数组的长度
     *
     * @param value           数值
     * @param length          字节数组的长度
     * @param isLowByteBefore 是否低位在前
     * @return byte[]
     * @author QuCheng Tech
     * @since 2025/11/8
     */
    public static int[] toByteArray(int value, int length, boolean isLowByteBefore) {
        if (length > 0x0) {
            int[] result = new int[length];

            //将传入的value每次右移1字节（8位），再跟0xFF做与运算就能得到一个字节上的数值
            int remainValue = value;//做右移移位运算后的剩余数值
            for (int i = 0; i < length; i++) {
                //初始化所有字节均为0
                int byteValue = 0x0;
                if (remainValue > 0x0) {
                    //判断是否需要进行移位，每次右移1字节，i=0时不进行右移
                    if (i > 0x0)
                        remainValue = remainValue >> 0x8;

                    //与0xFF做与运算得到当前字节上的值
                    byteValue = remainValue & 0xFF;

                    //根据高低位的顺序对返回数组进行赋值
                    if (isLowByteBefore == false) {
                        //高位在前、低位在后；按从后到前对数组进行赋值
                        result[length - i - 1] = byteValue;
                    } else {
                        //低位在前、高位在后；按从前到后对数组进行赋值
                        result[i] = byteValue;
                    }
                }
            }

            return result;
        }

        return null;
    }

    /**
     * 将Byte集合转换为byte数组
     *
     * @param list Byte集合
     * @return byte[]
     * @author QuCheng Tech
     * @since 2025/11/8
     */
    public static byte[] toByteArray(List<Byte> list) {
        if (list != null && list.size() > 0x0) {
            byte[] result = new byte[list.size()];
            for (int i = 0; i < list.size(); i++) {
                Byte bt = list.get(i);
                byte b = (byte) 0x0;//默认为0
                if (bt != null)
                    b = (byte) (bt.byteValue() & 0xFF);//与0xFF做与运算，避免出现超过1字节的最大值

                result[i] = b;
            }

            return result;
        }

        return null;
    }

    /**
     * byte转换为Hex字符串
     *
     * @param b byte值
     * @return java.lang.String
     * @author QuCheng Tech
     * @since 2025/11/7
     */
    public static String toHexString(byte b) {
        return String.format("%02X", b & 0xFF);
        //return toHexString(new byte[]{b});
    }

    /**
     * int数值转换为Hex字符串，int数值当做1字节数据
     *
     * @param value int数值
     * @return java.lang.String
     * @author QuCheng Tech
     * @since 2025/11/8
     */
    public static String toHexString(int value) {
        return String.format("%02X", value & 0xFF);
        //return toHexString(new byte[]{b});
    }

    /**
     * byte数组转换为十六进制字符串，每个byte转换为2个字符（不够的前面补0)
     *
     * @param bytes byte数组
     * @return java.lang.String
     * @author QuCheng Tech
     * @since 2025/11/7
     */
    public static String toHexString(byte[] bytes) {
        if (bytes != null && bytes.length > 0x0) {
            StringBuilder sbHex = new StringBuilder();
            for (byte b : bytes) {
                String byteHex = Integer.toHexString(b & 0xFF);
                //不足2个字符的前面补0
                if (byteHex.length() == 1)
                    sbHex.append("0" + byteHex);
                else
                    sbHex.append(byteHex);
            }

            //返回的十六进制字符串中全部使用大写
            return sbHex.toString().toUpperCase();
        }

        return null;
    }

    /**
     * int数值数组转换为Hex字符串，每个int数值当做1字节数据
     *
     * @param values int数值数组
     * @return java.lang.String
     * @author QuCheng Tech
     * @since 2025/11/8
     */
    public static String toHexString(int[] values) {
        if (values != null && values.length > 0x0) {
            StringBuilder sbHex = new StringBuilder();
            for (int b : values) {
                String byteHex = Integer.toHexString(b & 0xFF);
                //不足2个字符的前面补0
                if (byteHex.length() == 1)
                    sbHex.append("0" + byteHex);
                else
                    sbHex.append(byteHex);
            }

            //返回的十六进制字符串中全部使用大写
            return sbHex.toString().toUpperCase();
        }

        return null;
    }

    /**
     * 将十六进制字符串转换为字节数组
     *
     * @param hexString 十六进制字符串
     * @return 字节数组
     */
    public static byte[] hexStringToBytes(String hexString) {
        if (hexString == null || hexString.length() == 0) {
            return new byte[0];
        }

        // 移除可能存在的空格
        hexString = hexString.replaceAll("\\s", "");

        // 如果长度是奇数，在前面补0
        if (hexString.length() % 2 != 0) {
            hexString = "0" + hexString;
        }

        int len = hexString.length();
        byte[] data = new byte[len / 2];
        for (int i = 0; i < len; i += 2) {
            data[i / 2] = (byte) ((Character.digit(hexString.charAt(i), 16) << 4)
                    + Character.digit(hexString.charAt(i + 1), 16));
        }
        return data;
    }

    /**
     * byte转换为对应的Ascii字符
     *
     * @param b byte值
     * @return java.lang.String
     * @author QuCheng Tech
     * @since 2025/11/9
     */
    public static String toAsciiString(byte b) {
        int i = b;
        return toAsciiString(i);
    }

    /**
     * int值转换为对应的Ascii字符
     *
     * @param value int数值
     * @return java.lang.String
     * @author QuCheng Tech
     * @since 2025/11/9
     */
    public static String toAsciiString(int value) {
        char c = (char) (value & 0xFF); // 转换为char

        return String.valueOf(c);
    }

    /**
     * 字节数组转换为对应Ascii字符串，Ascii码值范围在0~127，因此必须是字节数组才能转换为Ascii字符
     *
     * @param bytes 字节数组
     * @return java.lang.String
     * @author QuCheng Tech
     * @since 2025/11/9
     */
    public static String toAsciiString(byte[] bytes) {
        //byte[] bytes = {72, 101, 108, 108, 111}; // ISO-8859-1编码的"Hello"的字节表示
        //String str = new String(bytes, StandardCharsets.ISO_8859_1);
        //System.out.println(str); // 输出: Hello
        //
        //byte[] utf8Bytes = {-28, -67, -96, -27, -91, -67}; // 示例UTF-8编码的字节，对应于汉字“中”
        //String str = new String(utf8Bytes, StandardCharsets.UTF_8);
        //System.out.println(str); // 输出: 中

        if (bytes != null && bytes.length > 0x0) {
            //不指定编码时采用默认编码，指定使用Ascii编码
            String str = new String(bytes, StandardCharsets.US_ASCII);

            return str;
        }

        return null;
    }

    /**
     * 获取指定字符串的字节数组，可以指定字符集
     *
     * @param str     字符串
     * @param charset 字符集
     * @return byte[]
     * @author QuCheng Tech
     * @since 2025/11/9
     */
    public static byte[] getBytes(String str, Charset charset) {
        if (str != null) {
            //字符串中如果是空格也是有对应的byte值
            if (charset != null)
                return str.getBytes(charset);

            //如果没有指定编码字符集，默认使用utf-8
            //根据需要指定字符串的编码
            //byte[] asciiBytes = str.getBytes(StandardCharsets.US_ASCII);
            //byte[] isoBytes = str.getBytes(StandardCharsets.ISO_8859_1);
            byte[] utf8Bytes = str.getBytes(StandardCharsets.UTF_8);
            //byte[] utf16Bytes = str.getBytes(StandardCharsets.UTF_16);
            return utf8Bytes;
        }

        return null;
    }
}
